package mapelements;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.Serializable;

import javax.swing.ImageIcon;


/**rappresenta la classe che indica come deve essere disegnato un certo oggetto concettuale.
 * Dato che si tratta di disegnare su un qualcosa, il Renderer possiede un concetto chiamato <strong>drawingComponent</strong>:
 * il drawingComponent è il componente su cui il renderer è disegnato. Nono tutti i renderer necessita di conoscere tale componente,
 * ma a molti basta sapere il suo Graphics; invece per alcuni renderer (come quell idotati di animazione) conoscere tale componente
 * è indispensabile per attuare l'animazione. è possibile settare il drawingComponent attraverso l'opportuno metodo {@link #setDrawingComponent(Component)}
 * 
 * @author koldar
 * @version 1.6
 */
public abstract class Renderer implements Serializable,Cloneable{
	
	private static final long serialVersionUID = -4623496732993153985L;
	
	public Renderer(){
		super();
	}
	
	/**utilizzando sia {@link #setDrawingComponent(Component)} che {@link #getDrawingComponent()} costruisce il nuovo renderer ottenendo
	 * 
	 * @param otherrenderer
	 */
	public Renderer(Renderer otherrenderer){
		super();
		this.setDrawingComponent(otherrenderer.getDrawingComponent());
	}
	
	/**indica la lista di istruzioni che devono essere eseguite per far capire ad un particolare Renderer
	 * su quale oggetto di tipo Component tale Renderer va disegnato. Alla radice dei Renderer tale metodo
	 * è vuoto. Questo metodo serve principalmente ai renderer animati in quanto (quando vengono serializzati) bisogna
	 * ristabilire il Component che li dipingerà. Evocare questo metodo per i renderer animati significa spesso <strong>far partire l'animazione (start)</strong>.
	 * Per questo ogni software dovrebbe (durante l'apertura di una nuova mappa) richiamare questo metodo.
	 * 
	 * @param parent il componente (o un componente che lo contiene) su cui il renderer sarà disegnato
	 */
	public void setDrawingComponent(Component parent){
	}
	
	/**
	 * 
	 * @return il componente che si occupa di disegnare il nostro Renderer. Di default il metodo ritorna NULL, ma può essere implementato
	 * a piacimento. Solitamente tale metodo è utile in caso di Renderer animati
	 */
	public Component getDrawingComponent(){
		return null;
	}
	
	/**indica la lista di istruzioni che devono essere eseguite per
	 * disegnare correttamente il renderer sul contesto grafico passato come parametro
	 * 
	 * @param g
	 * @return un'immagine (istantanea) di come è visualizzato il Renderer
	 */
	public abstract BufferedImage drawRenderer(Graphics g);
	
	/**esegue le istruzioni finali quando il Renderer deve essere congelato. Di default questo metodo è vuoto ma in alcune implementazioni
	 * dei Renderer (come i Renderer animati) è necessario riempire questo metodo con operazioni di terminazione (chiusura di thread ad esempio).
	 * La non eliminazione di questi Thread residui incide pesantemente sulle prestazioni ed inoltre potrebbe generare spiacevoli errori
	 */
	public void terminate(){
		
	}
	
	/**esegue le istruzioni per avviare l'eventuale animazione del Renderer. Non sempre il Renderer ne ha una.
	 * 
	 * @throws IllegalThreadStateException nel caso in cui l'animazione sia già stata avviata
	 */
	public void start() throws IllegalThreadStateException{
		
	}
	
	/**mette in pausa questo renderer. Questo metodo dovrebbe essere sovrascritto solo in caso di renderers animati
	 * 
	 */
	public void pause(){
		
	}
	
	/**riavvia un renderer che era stato precedentemente messo in pausa (tramite {@link #pause()}). Questo metodo dovrebbe essere
	 * sovrascritto solo in caso di Renderers animati.
	 * 
	 */
	public void restart(){
		
	}
	
	@Override
	public Renderer clone()throws CloneNotSupportedException{
		Renderer cloned=(Renderer) super.clone();
		return cloned;
	}
}
